package com.siecomzg.tool;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;


public class ByteTool {

    public static byte[] byteConvert32Bytes(BigInteger n)
    {
        byte tmpd[] = (byte[])null;
        if(n == null)
        {
            return null;
        }

        if(n.toByteArray().length == 33)
        {
            tmpd = new byte[32];
            System.arraycopy(n.toByteArray(), 1, tmpd, 0, 32);
        }
        else if(n.toByteArray().length == 32)
        {
            tmpd = n.toByteArray();
        }
        else
        {
            tmpd = new byte[32];
            for(int i = 0; i < 32 - n.toByteArray().length; i++)
            {
                tmpd[i] = 0;
            }
            System.arraycopy(n.toByteArray(), 0, tmpd, 32 - n.toByteArray().length, n.toByteArray().length);
        }
        return tmpd;
    }

    /**
     *
     *
     * @param b
     * @return
     */
    public static BigInteger byteConvertInteger(byte[] b)
    {
        if (b[0] < 0)
        {
            byte[] temp = new byte[b.length + 1];
            temp[0] = 0;
            System.arraycopy(b, 0, temp, 1, b.length);
            return new BigInteger(temp);
        }
        return new BigInteger(b);
    }

    public static void reversal(byte[] data) {
        int length = data.length;
        for (int i = 0; i < length / 2; i++) {
            byte temp = data[i];
            data[i] = data[length - 1 - i];
            data[length - 1 - i] = temp;
        }
    }
    /**
     * 单字节异或
     *
     * @param src1
     * @param src2
     * @return
     */
    public static byte byteXOR(byte src1, byte src2) {
        return (byte) ((src1 & 0xFF) ^ (src2 & 0xFF));
    }

    /**
     * 字节数组异或
     *
     * @param src1
     * @param src2
     * @return
     */
    public static byte[] bytesXOR(byte[] src1, byte[] src2) {
        int length = src1.length;
        if (length != src2.length) {
            return null;
        }
        byte[] result = new byte[length];
        for (int i = 0; i < length; i++) {
            result[i] = byteXOR(src1[i], src2[i]);
        }
        return result;
    }
    /**
     * 把公钥 Modul值没有248 位字节的 全部用0代替补充至248字节 GJ 2015/7/20
     * @param datas
     * @return
     */
    public static byte[] ComplementaryData(byte[] datas) {
        byte[] data = new byte[284];
        int j = 0;
        for (int i = 0; i < 284; i++) {
            if (i == 8) {
                if ((datas[8] & 0x0FF) != 248) {
                    byte[] modul = new byte[248];
                    System.arraycopy(datas, 9, modul, 0, (datas[8] & 0x0FF));
                    System.arraycopy(modul, 0, data, 9, modul.length);
                    i = 256;
                    j = 9 + (datas[8] & 0x0FF);
                    data[8] = (byte) (datas[8] & 0x0FF);
                    continue;
                }
            }
            if (j == 0) {
                data[i] = datas[i];
            } else {
                data[i] = datas[j];
                j++;
            }
        }
        return data;

    }
    /**
     * 获取以0x00结尾的byte数据长度
     * @param content
     * @return
     */
    public static int getBytesLength(byte[] content) {
        int i = 0;
        for (int j = 0; j < content.length; j++) {
            if (content[j] != 0)
                i++;
            else
                break;
        }
        return i;

    }
    /**
     * 两个数组合并
     * @param byte_1
     * @param byte_2
     * @return
     */
    public static byte[] byteMerger(byte[] byte_1, byte[] byte_2) {
        byte[] byte_3 = new byte[byte_1.length + byte_2.length];
        System.arraycopy(byte_1, 0, byte_3, 0, byte_1.length);
        System.arraycopy(byte_2, 0, byte_3, byte_1.length, byte_2.length);
        return byte_3;
    }
    /**
     * int型转为2byte
     * @param i
     * @return
     */
    public static byte[] int2Bytes(int i) {
        byte[] result = new byte[2];
        result[0] = (byte) ((i >> 8) & 0xFF);
        result[1] = (byte) (i & 0xFF);
        return result;
    }

    /**
     * int转为4个字节的bytes
     * @param i
     * @return
     */
    public static byte[] intTo4bytes(int i) {
        byte[] a = new byte[4];
        a[0] = (byte) ((0xff000000 & i) >> 24);
        a[1] = (byte) ((0xff0000 & i) >> 16);
        a[2] = (byte) ((0xff00 & i) >> 8);
        a[3] = (byte) (0xff & i);

        return a;

    }
    /**
     * byte数组转为hexString
     * @param b
     * @return
     */
    public static String byte2hex(byte[] b, int offset, int length, boolean withSpace) {
        StringBuffer buffer = new StringBuffer();
        String stmp = "";

        for (int n = offset; n < length; n++) {
            stmp = (Integer.toHexString(b[n] & 0XFF));
            if (stmp.length() == 1)
                buffer.append("0" + stmp);
            else
                buffer.append(stmp);
            if(withSpace){
                if(n!=length)
                    buffer.append(" ");

            }
        }

        return buffer.toString().toUpperCase();
    }
    /**
     * byte数组转为hexString
     * @param b
     * @return
     */
    public static String byte2hex(byte[] b) {
        StringBuffer hs = new StringBuffer();
        String stmp = "";

        for (int n = 0; n < b.length; n++) {
            stmp = (Integer.toHexString(b[n] & 0XFF));
            if (stmp.length() == 1)
                hs.append("0").append(stmp);
            else
                hs.append(stmp);
        }

        return hs.toString().toUpperCase();
    }
    /**
     * int转为一个字节的byte数组
     * @param num
     * @return
     */
    public static byte[] int2OneByte(int num) {
        byte[] result = new byte[1];
        result[0] = (byte) (num & 0x000000ff);
        return result;
    }
    /**
     * 16进制字符串转为对应的byte数组
     * @param
     * @return
     */
    public static byte[] hexStr2BytesWithSpace(String src) {
        String[] strarray=src.split(" ");
        int l = strarray.length;
        byte[] ret = new byte[l];
        for (int i = 0; i < l; i++) {
            ret[i] = (byte) Integer.parseInt(strarray[i],
                    16);
        }
        return ret;
    }

    /**
     * 16进制字符串转为对应的byte数组
     * @param
     * @return
     */
    public static byte[] hexStr2Bytes(String src) {
        int l = src.length() / 2;
        byte[] ret = new byte[l];
        try {
            for (int i = 0; i < l; i++) {
                ret[i] = (byte) Integer.parseInt(src.substring(i * 2, i * 2 + 2),
                        16);
            }
        }catch (NumberFormatException e){

            e.printStackTrace();
            return ret;
        }
        return ret;
    }


    public static byte[] getBytes(String s) {
        int len = s.length();
        byte[] destAray = null;
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        for (int i = 0; i < len; i++) {
            int v = s.charAt(i);
            bos.write((byte) ((v >>> 8) & 0xFF));
            bos.write((byte) ((v >>> 0) & 0xFF));
        }
        try {
            bos.flush();
        } catch (IOException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
        destAray = bos.toByteArray();
        try {
            bos.close();
        } catch (IOException e) {
        }

        return destAray;

    }

    /**
     * 16进制字符串转二进制字符串
     *
     * @param hexString
     * @return
     */
    public static String hexString2binaryString(String hexString) {
        if (hexString == null || hexString.length() % 2 != 0)
            return null;
        String bString = "", tmp;
        for (int i = 0; i < hexString.length(); i++) {
            tmp = "0000"
                    + Integer.toBinaryString(Integer.parseInt(
                    hexString.substring(i, i + 1), 16));
            bString += tmp.substring(tmp.length() - 4);
        }
        return bString;
    }

    /**
     * 16进制字符串转为其代表的bytes所对应的String
     *
     * @param all
     * @return
     */

    public static String HexStringArrToString(String[] all) {

        int length = all.length;
        byte[] bytes = new byte[length];
        for (int i = 0; i < length; i++) {
            bytes[i] = (byte) Integer.parseInt(all[i], 16);
        }
        return new String(bytes);
    }

    /**
     * byte2int
     * 数组转int型
     * @param b
     * @param offset
     * @return
     */
    public static int byteArrayToInt(byte[] b, int offset) {
        int value = 0;
        for (int i = 0; i < 4; i++) {
            int shift = (4 - 1 - i) * 8;
            value += (b[i + offset] & 0x000000FF) << shift;

        }
        return value;
    }
    /**
     * 数组Toint
     * @param b
     * @return
     */
    public static int byteArray2int(byte[] b) {
        byte[] a = new byte[4];
        int i = a.length - 1, j = b.length - 1;
        for (; i >= 0; i--, j--) {
            if (j >= 0)
                a[i] = b[j];
            else
                a[i] = 0;
        }
        int v0 = (a[0] & 0xff) << 24;
        int v1 = (a[1] & 0xff) << 16;
        int v2 = (a[2] & 0xff) << 8;
        int v3 = (a[3] & 0xff);
        return v0 + v1 + v2 + v3;
    }
    /**
     * short型转数组
     * @param b
     * @param x
     * @param offset
     */

    public static void ShortToBytes(byte[] b, short x, int offset) {
        if (b.length - offset >= 2) {
            b[(offset + 1)] = (byte) (x >> 8);
            b[(offset + 0)] = (byte) (x >> 0);
        }
    }
    /**
     * 数组转short
     * @param b
     * @param offset
     * @return
     */
    public static short BytesToShort(byte[] b, int offset) {
        short x = 0;
        if (b.length - offset >= 2) {
            x = (short) (b[(offset + 1)] << 8 | b[(offset + 0)] & 0xFF);
        }

        return x;
    }
    /**
     *单字节转16进制数
     */
    public static String byteToHexString(byte b) {
        StringBuffer sbBuffer = new StringBuffer();
        sbBuffer.append("0123456789ABCDEF".charAt(b >> 4 & 0xF));
        sbBuffer.append("0123456789ABCDEF".charAt(b & 0xF));
        return sbBuffer.toString();
    }
    /**
     * 带偏移的int过程式
     * @param b
     * @param x
     * @param offset
     */
    public static void IntToBytes(byte[] b, int x, int offset) {
        if (b.length - offset >= 4) {
            b[(offset + 3)] = (byte) (x >> 24);
            b[(offset + 2)] = (byte) (x >> 16);
            b[(offset + 1)] = (byte) (x >> 8);
            b[(offset + 0)] = (byte) (x >> 0);
        }
    }
    /**
     *
     * @param b
     * @param offset
     * @return
     */
    public static int BytesToInt(byte[] b, int offset) {
        int x = 0;
        if (b.length - offset >= 4) {
            x = (b[(offset + 3)] & 0xFF) << 24 | (b[(offset + 2)] & 0xFF) << 16
                    | (b[(offset + 1)] & 0xFF) << 8
                    | (b[(offset + 0)] & 0xFF) << 0;
        }

        return x;
    }

    public static void LongToBytes(byte[] b, long x, int offset) {
        if (b.length - offset >= 8) {
            b[(offset + 7)] = (byte) (int) (x >> 56);
            b[(offset + 6)] = (byte) (int) (x >> 48);
            b[(offset + 5)] = (byte) (int) (x >> 40);
            b[(offset + 4)] = (byte) (int) (x >> 32);
            b[(offset + 3)] = (byte) (int) (x >> 24);
            b[(offset + 2)] = (byte) (int) (x >> 16);
            b[(offset + 1)] = (byte) (int) (x >> 8);
            b[(offset + 0)] = (byte) (int) (x >> 0);
        }
    }

    public static long BytesToLong(byte[] b, int offset) {
        long x = 0L;
        if (b.length - offset >= 8) {
            x = (b[(offset + 7)] & 0xFF) << 56 | (b[(offset + 6)] & 0xFF) << 48
                    | (b[(offset + 5)] & 0xFF) << 40
                    | (b[(offset + 4)] & 0xFF) << 32
                    | (b[(offset + 3)] & 0xFF) << 24
                    | (b[(offset + 2)] & 0xFF) << 16
                    | (b[(offset + 1)] & 0xFF) << 8
                    | (b[(offset + 0)] & 0xFF) << 0;
        }

        return x;
    }

    public static void CharToBytes(byte[] b, char ch, int offset) {
        if (b.length - offset >= 2) {
            int temp = ch;
            for (int i = 0; i < 2; i++) {
                b[(offset + i)] = new Integer(temp & 0xFF).byteValue();
                temp >>= 8;
            }
        }
    }

    public static byte charToByte(char c) {

        return (byte) "0123456789ABCDEF".indexOf(c);
    }

    public static char BytesToChar(byte[] b, int offset) {
        int s = 0;

        if (b.length - offset >= 2) {
            if (b[(offset + 1)] > 0)
                s += b[(offset + 1)];
            else
                s += 256 + b[(offset + 0)];
            s *= 256;
            if (b[(offset + 0)] > 0)
                s += b[(offset + 1)];
            else {
                s += 256 + b[(offset + 0)];
            }
        }
        char ch = (char) s;
        return ch;
    }

    public static void FloatToBytes(byte[] b, float x, int offset) {
        if (b.length - offset >= 4) {
            int l = Float.floatToIntBits(x);
            for (int i = 0; i < 4; i++) {
                b[(offset + i)] = new Integer(l).byteValue();
                l >>= 8;
            }
        }
    }

    public static float BytesToFloat(byte[] b, int offset) {
        int l = 0;

        if (b.length - offset >= 4) {
            l = b[(offset + 0)];
            l &= 255;
            l = (int) (l | b[(offset + 1)] << 8);
            l &= 65535;
            l = (int) (l | b[(offset + 2)] << 16);
            l &= 16777215;
            l = (int) (l | b[(offset + 3)] << 24);
        }

        return Float.intBitsToFloat(l);
    }

    public static void DoubleToBytes(byte[] b, double x, int offset) {
        if (b.length - offset >= 8) {
            long l = Double.doubleToLongBits(x);
            for (int i = 0; i < 4; i++) {
                b[(offset + i)] = new Long(l).byteValue();
                l >>= 8;
            }
        }
    }

    public static double BytesToDouble(byte[] b, int offset) {
        long l = 0L;

        if (b.length - offset >= 8) {
            l = b[0];
            l &= 255L;
            l |= b[1] << 8;
            l &= 65535L;
            l |= b[2] << 16;
            l &= 16777215L;
            l |= b[3] << 24;
            l &= 4294967295L;
            l |= b[4] << 32;
            l &= 1099511627775L;
            l |= b[5] << 40;
            l &= 281474976710655L;
            l |= b[6] << 48;
            l &= 72057594037927935L;
            l |= b[7] << 56;
        }

        return Double.longBitsToDouble(l);
    }

    public static short toLH(short n) {
        byte[] b = new byte[2];
        b[0] = (byte) (n & 0xFF);
        b[1] = (byte) (n >> 8 & 0xFF);

        short ret = BytesToShort(b, 0);
        return ret;
    }

    public static short toHL(short n) {
        byte[] b = new byte[2];
        b[1] = (byte) (n & 0xFF);
        b[0] = (byte) (n >> 8 & 0xFF);

        short ret = BytesToShort(b, 0);
        return ret;
    }

    public static int toLH(int n) {
        byte[] b = new byte[4];
        b[0] = (byte) (n & 0xFF);
        b[1] = (byte) (n >> 8 & 0xFF);
        b[2] = (byte) (n >> 16 & 0xFF);
        b[3] = (byte) (n >> 24 & 0xFF);

        int ret = BytesToInt(b, 0);
        return ret;
    }

    public static int toHL(int n) {
        byte[] b = new byte[4];
        b[3] = (byte) (n & 0xFF);
        b[2] = (byte) (n >> 8 & 0xFF);
        b[1] = (byte) (n >> 16 & 0xFF);
        b[0] = (byte) (n >> 24 & 0xFF);

        int ret = BytesToInt(b, 0);
        return ret;
    }

    public static long toLH(long n) {
        byte[] b = new byte[8];
        b[0] = (byte) (int) (n & 0xFF);
        b[1] = (byte) (int) (n >> 8 & 0xFF);
        b[2] = (byte) (int) (n >> 16 & 0xFF);
        b[3] = (byte) (int) (n >> 24 & 0xFF);
        b[4] = (byte) (int) (n >> 32 & 0xFF);
        b[5] = (byte) (int) (n >> 40 & 0xFF);
        b[6] = (byte) (int) (n >> 48 & 0xFF);
        b[7] = (byte) (int) (n >> 56 & 0xFF);

        long ret = BytesToLong(b, 0);
        return ret;
    }

    public static long toHL(long n) {
        byte[] b = new byte[8];
        b[7] = (byte) (int) (n & 0xFF);
        b[6] = (byte) (int) (n >> 8 & 0xFF);
        b[5] = (byte) (int) (n >> 16 & 0xFF);
        b[4] = (byte) (int) (n >> 24 & 0xFF);
        b[3] = (byte) (int) (n >> 32 & 0xFF);
        b[2] = (byte) (int) (n >> 40 & 0xFF);
        b[1] = (byte) (int) (n >> 48 & 0xFF);
        b[0] = (byte) (int) (n >> 56 & 0xFF);

        long ret = BytesToLong(b, 0);
        return ret;
    }


    public static byte[] short2byte(short s) {
        byte[] size = new byte[2];
        size[0] = (byte) (s >>> 8);
        short temp = (short) (s << 8);
        size[1] = (byte) (temp >>> 8);

        // size[0] = (byte) ((s >> 8) & 0xff);
        // size[1] = (byte) (s & 0x00ff);
        return size;
    }
    /**
     * 两个byte合成short
     * @param b1
     * @param b2
     * @return
     */
    public static short getShort(byte b1, byte b2) {
        short temp = 0;
        temp |= (b1 & 0xff);
        temp <<= 8;
        temp |= (b2 & 0xff);
        return temp;
    }

    /**
     * zip流压缩
     * @param
     * @return
     * @throws IOException
     */
    public static byte[] compress(byte[] data) throws IOException {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        GZIPOutputStream gzip = new GZIPOutputStream(out);
        gzip.write(data);
        gzip.close();
        return out.toByteArray();
    }

    /**
     * zip流解压
     * @param
     * @return
     * @throws IOException
     */
    public static byte[] uncompress(byte[] data) throws IOException {

        ByteArrayOutputStream out = new ByteArrayOutputStream();
        ByteArrayInputStream in = new ByteArrayInputStream(data);
        GZIPInputStream gunzip = new GZIPInputStream(in);
        byte[] buffer = new byte[256];
        int n;
        while ((n = gunzip.read(buffer)) >= 0) {
            out.write(buffer, 0, n);
        }
        return out.toByteArray();
    }
    /**
     * 合成
     * @param srcArrays
     * @return
     */
    public static byte[] streamCopy(List<byte[]> srcArrays) {
        byte[] destAray = null;
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        try {
            for (byte[] srcArray : srcArrays) {

                bos.write(srcArray);
            }
            bos.flush();
            destAray = bos.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                bos.close();
            } catch (IOException e) {
            }
        }
        return destAray;
    }
    /**
     * 数组转hexString限定长度
     * @param b
     * @param leng
     * @return
     */
    public static String bytearrayToHexString(byte[] b, int leng) {
        StringBuffer strbuf = new StringBuffer();
        for (int i = 0; i < leng; i++) {
            strbuf.append("0123456789ABCDEF"
                    .charAt((byte)((b[i] & 0xF0) >> 4)));
            strbuf.append("0123456789ABCDEF".charAt((byte)(b[i] & 0xF)));
//			strbuf.append(" ");
        }
        return strbuf.toString();
    }
    /**
     * byte转为String，遇0x00结尾终止
     * @param b
     * @return
     */
    public static String bytesToString(byte[] b) {
        StringBuffer result = new StringBuffer("");
        int length = b.length;

        for (int i = 0; i < length; i++) {
            char ch = (char)(b[i] & 0xFF);
            if (ch == 0)
            {
                break;
            }
            result.append(ch);
        }

        return result.toString();
    }
    /**
     * Bits to Byte[]
     * @param bits
     * @return
     */
    public static byte[] BitsToBytesArr(String bits){

        //如果不是8的倍数，前段补零
        if(bits.length()%8 != 0){
            bits = complemented(bits, 8-bits.length()%8);
        }
        byte[] ret = new byte[bits.length()/8];
        for(int j = 0; j < bits.length()/8; j++){
            ret[j] = BitToByte(bits.substring(j*8,(j+1)*8));
        }
        return ret;
    }

    /**
     * bit转byte
     */
    public static byte BitToByte(String bitsStr) {
        int re, len;
        if (null == bitsStr) {
            return 0;
        }
        len = bitsStr.length();
        if (len != 4 && len != 8) {
            return 0;
        }
        if (len == 8) {// 8 bit处理
            if (bitsStr.charAt(0) == '0') {// 正数
                re = Integer.parseInt(bitsStr, 2);
            } else {// 负数
                re = Integer.parseInt(bitsStr, 2) - 256;
            }
        } else {//4 bit处理
            re = Integer.parseInt(bitsStr, 2);
        }
        return (byte) re;
    }

    /**
     * Byte[] to Bits
     * @param M
     * @return Bits.length = 8*k;
     */
    public static String ByteArrToBits(byte[] M) {

        StringBuffer ret = new StringBuffer();
        for(byte b:M){
            ret.append( (byte) ((b >> 7) & 0x1));
            ret.append( (byte) ((b >> 6) & 0x1));
            ret.append( (byte) ((b >> 5) & 0x1));
            ret.append( (byte) ((b >> 4) & 0x1));
            ret.append( (byte) ((b >> 3) & 0x1));
            ret.append( (byte) ((b >> 2) & 0x1));
            ret.append( (byte) ((b >> 1) & 0x1));
            ret.append( (byte) ((b >> 0) & 0x1));
        }
        return ret.toString();
    }

    /**
     * byte to bits
     * @param b
     * @return
     */
    public static String byteToBit(byte b) {
        return ""
                + (byte) ((b >> 7) & 0x1) + (byte) ((b >> 6) & 0x1)
                + (byte) ((b >> 5) & 0x1) + (byte) ((b >> 4) & 0x1)
                + (byte) ((b >> 3) & 0x1) + (byte) ((b >> 2) & 0x1)
                + (byte) ((b >> 1) & 0x1) + (byte) ((b >> 0) & 0x1);
    }


    /**
     * 将ArrayList转化为二进制数组
     *
     * @param list
     *            ArrayList对象
     * @return 二进制数组
     */
    public static byte[] getInfoBytesFromObject(ArrayList<Point> list) {
        ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream();
        try {
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(
                    arrayOutputStream);
            objectOutputStream.writeObject(list);
            objectOutputStream.flush();
            byte[] data = arrayOutputStream.toByteArray();
            objectOutputStream.close();
            arrayOutputStream.close();
            return data;
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 从二进制数组转换Arrayist对象
     * @param bytes 二进制数组
     * @return ArrayList返回对象
     */
    public static ArrayList<Point> getInfoListFromBytes(byte[] bytes) {
        ByteArrayInputStream arrayInputStream = new ByteArrayInputStream(bytes);
        try {
            ObjectInputStream inputStream = new ObjectInputStream(
                    arrayInputStream);
            ArrayList<Point> list = (ArrayList<Point>) inputStream
                    .readObject();
            inputStream.close();
            arrayInputStream.close();
            return list;
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 将比特串str前段补klen位0
     *
     * @param str
     * @param klen
     * @return
     */
    public static String complemented(String str, int klen) {
        if (klen == 0) {
            return str;
        }
        if (klen == 1) {
            return "0" + str;
        }
        return complemented("0" + str, klen - 1);
    }
}
